package com.lyn.nv21;

import android.graphics.Bitmap;
import android.view.Surface;

public class Nv21 {

    private static byte[] BITMAP_TO_NV21_DATA;

    public byte[] bitmapToNV21(final Bitmap bitmap) {
        if (bitmap == null) {
            return null;
        }
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        boolean isExist = false;
        if (BITMAP_TO_NV21_DATA != null) {
            if (BITMAP_TO_NV21_DATA.length == width * height * 3 / 2) {
                isExist = true;
            }
        }
        if (!isExist) {
            BITMAP_TO_NV21_DATA = new byte[width * height * 3 / 2];
        }
        toBitmap(bitmap, BITMAP_TO_NV21_DATA);
        return BITMAP_TO_NV21_DATA;
    }


    private static byte[] CENTER_CUT_NV21_DATA;

    public byte[] centerCutNV21(byte[] srcNV21, int srcWidth, int srcHeight, int outWidth, int outHeight) {
        if (srcWidth < outWidth || srcHeight < outHeight) {
            return srcNV21;
        }
        if (CENTER_CUT_NV21_DATA == null) {
            CENTER_CUT_NV21_DATA = new byte[outWidth * outHeight * 3 / 2];
        } else {
            if (CENTER_CUT_NV21_DATA.length != outWidth * outHeight * 3 / 2) {
                CENTER_CUT_NV21_DATA = new byte[outWidth * outHeight * 3 / 2];
            }
        }
        int outLeft = (srcWidth - outWidth) / 2;
        int outTop = (srcHeight - outHeight) / 2;
        clip(srcNV21, srcWidth, srcHeight, CENTER_CUT_NV21_DATA, outLeft, outTop, outWidth, outHeight);
        return CENTER_CUT_NV21_DATA;
    }

    private static byte[] CUT_NV21_DATA;

    public byte[] cutNV21(byte[] srcNV21, int srcWidth, int srcHeight, int outLeft, int outTop, int outWidth, int outHeight) {
        if (CUT_NV21_DATA == null) {
            CUT_NV21_DATA = new byte[outWidth * outHeight * 3 / 2];
        } else {
            if (CUT_NV21_DATA.length != outWidth * outHeight * 3 / 2) {
                CUT_NV21_DATA = new byte[outWidth * outHeight * 3 / 2];
            }
        }
        clip(srcNV21, srcWidth, srcHeight, CUT_NV21_DATA, outLeft, outTop, outWidth, outHeight);
        return CUT_NV21_DATA;
    }


    public void mirrorNV21(byte[] srcNV21, int srcWidth, int srcHeight) {
        mirror(srcNV21, srcWidth, srcHeight);
    }


    private static byte[] ROTATE_NV21_DATA;

    public byte[] rotateNV21(byte[] srcNV21, int srcWidth, int srcHeight, Rotate rotate) {
        if (srcNV21 == null || rotate == null) return null;
        if (ROTATE_NV21_DATA == null) {
            ROTATE_NV21_DATA = new byte[srcWidth * srcHeight * 3 / 2];
        } else {
            if (ROTATE_NV21_DATA.length != srcWidth * srcHeight * 3 / 2) {
                ROTATE_NV21_DATA = new byte[srcWidth * srcHeight * 3 / 2];
            }
        }
        switch (rotate) {
            case ROTATE_90:
                rotate(srcNV21, srcWidth, srcHeight, ROTATE_NV21_DATA, 90);
                break;
            case ROTATE_180:
                rotate(srcNV21, srcWidth, srcHeight, ROTATE_NV21_DATA, 180);
                break;
            case ROTATE_270:
                rotate(srcNV21, srcWidth, srcHeight, ROTATE_NV21_DATA, 270);
                break;
        }
        return ROTATE_NV21_DATA;
    }

    private static int[] NV21_TO_BGR_DATA;

    public int[] nv21ToRgb(byte[] srcNV21, int srcWidth, int srcHeight, boolean isRgb) {
        if (NV21_TO_BGR_DATA == null) {
            NV21_TO_BGR_DATA = new int[srcWidth * srcHeight];
        } else {
            if (NV21_TO_BGR_DATA.length != srcWidth * srcHeight) {
                NV21_TO_BGR_DATA = new int[srcWidth * srcHeight];
            }
        }
        toRgb(srcNV21, srcWidth, srcHeight, NV21_TO_BGR_DATA, isRgb);
        return NV21_TO_BGR_DATA;
    }


    public Bitmap nv21ToBitmap(byte[] srcNV21, int srcWidth, int srcHeight) {
        int[] rgb = nv21ToRgb(srcNV21, srcWidth, srcHeight, false);
        return Bitmap.createBitmap(rgb, 0, srcWidth, srcWidth, srcHeight, Bitmap.Config.ARGB_8888);
    }

    public native void toBitmap(final Bitmap bitmap, byte[] outNv21);

    public native void toRgb(byte[] srcNV21, int srcNv21Width, int srcNv21Height, int[] outRgb, boolean isRgb);

    public native void clip(byte[] srcNV21, int srcNv21Width, int srcNv21Height, byte[] outNV21, int outNv21Left, int outNv21Top, int outNv21With, int outNv21Height);

    public native void mirror(byte[] srcNV21, int srcNv21Width, int srcNv21Height);

    public native void rotate(byte[] srcNV21, int srcNv21Width, int srcNv21Height, byte[] outNV21, int angle);


    public enum Rotate {
        ROTATE_90, ROTATE_180, ROTATE_270;
    }


    static {
        try {
            System.loadLibrary("Nv21");
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }
}
